#include "flash.h"


/***********************************************
*函数名称：SPI_Flash_Init
*功    能：flash芯片初始化
*入口参数：无
*返 回 值：无	
*备    注：无
************************************************/
void SPI_Flash_Init(void)
{
	SPI_InitStructure SPI_initStruct;

	GPIO_Init(_SPISSELPORT_, _SPISSELPIN_,  1, 0, 0);				// 输出，接CS

	SPIFlash_CS_Set;

	PORT_Init(_SPI0SCLKPORT_, _SPI0SCLKPIN_, FUNMUX1_SPI0_SCLK, 0);
	PORT_Init(_SPI0MOSIPORT_, _SPI0MOSIPIN_, FUNMUX0_SPI0_MOSI, 0);
	PORT_Init(_SPI0MISOPORT_, _SPI0MISOPIN_, FUNMUX1_SPI0_MISO, 1);
	
	SPI_initStruct.clkDiv = SPI_CLKDIV_4;
	SPI_initStruct.FrameFormat = SPI_FORMAT_SPI;
	SPI_initStruct.SampleEdge = SPI_FIRST_EDGE;
	SPI_initStruct.IdleLevel = SPI_LOW_LEVEL;
	SPI_initStruct.WordSize = 8;
	SPI_initStruct.Master = 1;
	SPI_initStruct.RXHFullIEn = 0;
	SPI_initStruct.TXEmptyIEn = 0;
	SPI_initStruct.TXCompleteIEn = 0;
	SPI_Init(SPI0, &SPI_initStruct);
	SPI_Open(SPI0);
}

/***********************************************
*函数名称：SPI_ReadWriteByte
*功    能：SPI读写一个字节
*入口参数：SPI要写入的数据
*返 回 值：SPI读到的数据
*备    注：无
************************************************/
uint8_t SPI_ReadWriteByte(uint8_t data)
{
	return SPI_ReadWrite(SPI0, data);
}


/***********************************************
*函数名称：SPI_ReadSR
*功    能：SPI读取状态寄存器
*入口参数：
*返 回 值：SPI读到的状态
*备    注：无
************************************************/
uint8_t SPI_ReadSR(void)   
{  
	uint8_t byte=0;   
	
	SPIFlash_CS_Clr;                                                              //使能器件   
	SPI_ReadWriteByte(W25X_ReadStatusReg);                                        //发送读取状态寄存器命令    
	byte=SPI_ReadWriteByte(0Xff);                                                 //读取一个字节  
	SPIFlash_CS_Set;                                                              //取消片选    
	
	return byte;
} 


/***********************************************
*函数名称：SPI_FLASH_WriteEnable
*功    能：SPI写使能
*入口参数：无
*返 回 值：无	
*备    注：无
************************************************/
void SPI_FLASH_WriteEnable(void)
{
	SPIFlash_CS_Clr;						                                                  //使能器件  
	SPI_ReadWriteByte(W25X_WriteEnable); 	                                        //发送写使能命令
	SPIFlash_CS_Set;						                                                  //取消片选    
}

/***********************************************
*函数名称：SPI_FLASH_WriteEnable
*功    能：SPI写禁止
*入口参数：无
*返 回 值：无	
*备    注：无
************************************************/
void SPI_FLASH_WriteDisable(void)
{
	SPIFlash_CS_Clr;						                                                  //使能器件  
	SPI_ReadWriteByte(W25X_WriteDisable); 	                                      //发送写禁止命令
	SPIFlash_CS_Set;						                                                  //取消片选    
}

/***********************************************
*函数名称：SPI_FLASH_ReadID
*功    能：flash芯片初始化
*入口参数：无
*返 回 值：//0XEF13,表示芯片型号为W25Q80  
				 	 //0XEF14,表示芯片型号为W25Q16    
					 //0XEF15,表示芯片型号为W25Q32  
					 //0XEF16,表示芯片型号为W25Q64 
					 //0XEF17,表示芯片型号为W25Q128 	
*备    注：无
************************************************/
uint16_t SPI_FLASH_ReadID(void)
{
	uint16_t Temp = 0;	  
	SPIFlash_CS_Clr;				    
	SPI_ReadWriteByte(0x90);                                                      //发送读取ID命令	    
	SPI_ReadWriteByte(0x00); 	    
	SPI_ReadWriteByte(0x00); 	    
	SPI_ReadWriteByte(0x00); 	 			   
	Temp|=SPI_ReadWriteByte(0xFF)<<8;
	Temp|=SPI_ReadWriteByte(0xFF);	 
	SPIFlash_CS_Set;				    
	return Temp;
}


/***********************************************
*函数名称：SPI_FLASH_Read
*功    能：读取SPI FLASH
*入口参数：pBuffer: 数据存储区
           ReadAddr:开始读取的地址(24bit)
           NumByteToRead:要读取的字节数(最大65535)
*返 回 值：	
*备    注：无
************************************************/
void SPI_FLASH_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
{
	uint16_t i;
	SPIFlash_CS_Clr;				    
	SPI_ReadWriteByte(W25X_ReadData);                                           	//发送读取命令   
	SPI_ReadWriteByte(((ReadAddr & 0xff0000)>>16));  	                            //发送24bit地址    
	SPI_ReadWriteByte(((ReadAddr & 0xff00)>>8));   
	SPI_ReadWriteByte(  ReadAddr & 0xff);   
  for(i=0;i<NumByteToRead;i++)
	{ 
		pBuffer[i]=SPI_ReadWriteByte(0XFF);                                       	//循环读数  
  }
	SPIFlash_CS_Set;	
}

/***********************************************
*函数名称：SPI_FLASH_WritePage
*功    能：写入数据
*入口参数：pBuffer: 数据存储区
           WriteAddr:开始写入的地址(24bit)
           NumByteToWrite:要写入的字节数(最大256)
*返 回 值：无
*备    注：无
************************************************/
void SPI_FLASH_WritePage(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
 	uint16_t i;  
	SPI_FLASH_WriteEnable();                            	                        //写使能
	SPIFlash_CS_Clr;
	
  SPI_ReadWriteByte(W25X_PageProgram);                                        	//发送写页命令   
	SPI_ReadWriteByte(((WriteAddr & 0xff0000)>>16));  	                          //发送24bit地址    
	SPI_ReadWriteByte(((WriteAddr & 0xff00)>>8));   
	SPI_ReadWriteByte(  WriteAddr & 0xff);   
  for(i=0;i<NumByteToWrite;i++){
		SPI_ReadWriteByte(pBuffer[i]);//循环写数  
	}
	
	SPIFlash_CS_Set;
	
	SPI_FLASH_WaitBusy();					   		//等待写入结束
} 



/***********************************************
*函数名称：SPI_FLASH_WriteNoCheck
*功    能：无检验写SPI FLASH 
*入口参数：pBuffer: 数据存储区
           WriteAddr:开始写入的地址(24bit)
           NumByteToWrite:要写入的字节数
*返 回 值：无	
*备    注：无
************************************************/
void SPI_FLASH_WriteNoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 			 		 
	uint16_t pageremain;	   
	pageremain=256-WriteAddr%256; //单页剩余的字节数
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
	while(1)
	{
		SPI_FLASH_WritePage(pBuffer,WriteAddr,pageremain);
		if(NumByteToWrite==pageremain)break;//写入结束了
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;	

			NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
			if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
			else pageremain=NumByteToWrite; 	  //不够256个字节了
		}
	}
} 

/***********************************************
*函数名称：SPI_FLASH_Write
*功    能：在指定地址开始写入指定长度的数据
*入口参数：pBuffer: 数据存储区
           WriteAddr:开始写入的地址(24bit)
           NumByteToWrite:要写入的字节数
*返 回 值：无	
*备    注：无
************************************************/
uint8_t flashbuff[4096];

void SPI_FLASH_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 
	uint32_t secpos;
	uint16_t secoff;
	uint16_t secremain;
 	uint16_t i;
	uint8_t * W25QXX_BUF;
  W25QXX_BUF=flashbuff;	     
 	secpos=WriteAddr/4096;//扇区地址  
	secoff=WriteAddr%4096;//在扇区内的偏移
	secremain=4096-secoff;//扇区剩余空间大小

 	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
	while(1) 
	{	
		SPI_FLASH_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
		for(i=0;i<secremain;i++)//校验数据
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除
		}
		if(i<secremain)//需要擦除
		{
			SPI_FLASH_EraseSector(secpos);		//擦除这个扇区
			for(i=0;i<secremain;i++)	   		//复制
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];	  
			}
			SPI_FLASH_WriteNoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区

		}else SPI_FLASH_WriteNoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. 				   
		if(NumByteToWrite==secremain)break;//写入结束了
		else//写入未结束
		{
			secpos++;//扇区地址增1
			secoff=0;//偏移位置为0 	 

		   	pBuffer+=secremain;  				//指针偏移
			WriteAddr+=secremain;				//写地址偏移	   
		   	NumByteToWrite-=secremain;			//字节数递减
			if(NumByteToWrite>4096)secremain=4096;//下一个扇区还是写不完
			else secremain=NumByteToWrite;		//下一个扇区可以写完了
		}	 
	};	 
}


/***********************************************
*函数名称：SPI_FLASH_Write
*功    能：写一页
*入口参数：pBuffer: 数据存储区
           WriteAddr:开始写入的地址(24bit)
           NumByteToWrite:要写入的字节数
*返 回 值：无	
*备    注：无
************************************************/
void SPI_FLASH_EraseSector(uint32_t Dst_Addr)   
{  
 	Dst_Addr*=4096;
	SPI_FLASH_WriteEnable();                  	                                  //SET WEL 	 
	SPI_FLASH_WaitBusy();   
	SPIFlash_CS_Clr;                                                             	//使能器件   
	SPI_ReadWriteByte(W25X_SectorErase);                                         	//发送扇区擦除指令 
	SPI_ReadWriteByte(((Dst_Addr & 0xff0000)>>16));  	                            //发送24bit地址    
	SPI_ReadWriteByte(((Dst_Addr & 0xff00)>>8));   
	SPI_ReadWriteByte(  Dst_Addr & 0xff);   
	SPIFlash_CS_Set;                                                             	//取消片选     	      
  SPI_FLASH_WaitBusy();   				                                           		//等待擦除完成
}  


//等待空闲
void SPI_FLASH_WaitBusy(void)   
{   
	while((SPI_ReadSR()&0x01)==0x01);  		// 等待BUSY位清空
}  

//等待空闲
void SPI_FLASH_ChipErase(void)   
{
	SPI_FLASH_WriteEnable();                  	                                  //SET WEL 	 
	SPI_FLASH_WaitBusy();   				                                           		//等待擦除完成
	SPIFlash_CS_Clr;						                                                  //使能器件  
	SPI_ReadWriteByte(W25X_ChipErase); 	                                      //发送写禁止命令
	SPIFlash_CS_Set;	
	SPI_FLASH_WaitBusy();   				                                           		//等待擦除完成
} 
